package com.wyg.client;

import com.alibaba.csp.sentinel.Entry;
import com.wyg.coder.RPCDecoder;
import com.wyg.coder.RPCEncoder;
import com.wyg.model.User;
import com.wyg.protocol.RPCRequest;
import com.wyg.protocol.RPCResponse;
import com.wyg.service.UserService;
import com.wyg.zookeeper.Constant;
import com.wyg.zookeeper.ServiceDiscovery;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.codec.LengthFieldPrepender;

import java.util.List;
import java.util.concurrent.CountDownLatch;

/**
 * @description:
 * @author: WYG
 * @time: 2020/10/24 19:18
 */

public class RPCClient {
    private final String host;
    private final int port;
    private final CountDownLatch latch;
    public RPCClient(String host,int port) {
        this.host = host;
        this.port = port;
        this.latch = new CountDownLatch(1);
    }
    public RPCResponse send(RPCRequest rpcRequest) {
        EventLoopGroup eventExecutors = new NioEventLoopGroup();
        Bootstrap bootstrap = new Bootstrap();
        RPCResponse response = new RPCResponse();
        final RPCClientHandler clientHandler = new RPCClientHandler(rpcRequest, latch);
        try {
            bootstrap.group(eventExecutors)
                    .channel(NioSocketChannel.class).option(ChannelOption.TCP_NODELAY, true)
                    .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 3000)
                    .handler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            ch.pipeline()
                                    .addLast(new LengthFieldBasedFrameDecoder(65535, 0, 2, 0, 2))
                                    .addLast(new RPCDecoder(RPCResponse.class))
                                    .addLast(new LengthFieldPrepender(2))
                                    .addLast(new RPCEncoder(RPCRequest.class))
                                    .addLast(clientHandler);
                        }
                    });
            ChannelFuture future = bootstrap.connect(host, port).sync();
            latch.await();
            response = clientHandler.getResponse();

            if (response != null) {
                future.channel().close();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        // System.out.println("RPCClient Response:\t" + response.toString());
        return response;
    }

    public static void main(String[] args) throws Throwable {
        ServiceDiscovery serviceDiscovery = new ServiceDiscovery(Constant.ZK_CONNECT);
        RPCProxy rpcProxy = new RPCProxy(serviceDiscovery);
        UserService userService = rpcProxy.create(UserService.class);
        User user = null;
        try {
            user = userService.findUserById(1);
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        System.out.println("userService.findUserById远程调用结果:\t" + user.toString());
        try {
            User user1 = userService.findUserById(2);
        } catch (Throwable throwable) {
            System.out.println("服务端出现错误:\t" + throwable.getCause() + "\t请稍后再次尝试请求");
        }
    }
}
